#pragma once

#include<iostream>
#include"Connection.hpp"
#include"Protocol.hpp"
#include"Calculate.hpp"
#include"Log.hpp"

 const static int buffer_size=1024;

using namespace CalCulateNS;
using namespace Protocol;
class HandlerConnection
{
public:
    static void HandlerRequest(Connection* conn)
    {
        string& inbuffer=conn->InBuffer();
        string message;//表示一个符合协议的完整报文
        Factory factory;
        CalCulate calculate;//负责计算这个业务
        auto req=factory.BuildRequest();
        //1.明确报文边界，解决粘包问题
        while(Decode(inbuffer,&message))
        {
            //message是一个完整的报文，符合协议
            //2.反序列化
            if(!req->Deserialize(message))
                continue;
            //3.业务处理
            auto resp=calculate.Cal(req);
            //4.对响应进行序列化
            string responseStr;//
            resp->Serialize(&responseStr);
            //5.封装完整报文
            responseStr=Encode(responseStr);//??写的有所不同
            //6.将应答全部追加到outbuffer中
            conn->AddOutbuffer(responseStr);
        }
        //考虑发送的问题了
        if(!conn->OutBufferEmpty())
        {
            conn->_sender(conn);//对事件直接发——不代表能全部发完
        }
    }
    //在这里读取的时候，我们关心数据的格式吗？协议是什么样的吗？
    //不关心！！！我们只负责把本轮属于完全读取完毕——把读到的字节流数据，交给上层——由上层分析处理
    static void Recver(Connection* conn)
    {
        errno=0;
        char buffer[1024];
        while(true)
        {
            ssize_t n=recv(conn->SockFd(),buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                buffer[n]=0;
                conn->AddInBuffer(buffer);
            }
            else
            {
                if(errno==EAGAIN)break;
                else if(errno==EINTR)continue;
                else
                {
                    //真正的读取错误
                    conn->_execepter(conn);//将自己调回自己的异常处理
                    return;
                }
            }
        }
        cout<<endl;
        cout<<"sockfd# "<<conn->SockFd()<<":\n    "<<conn->InBuffer()<<endl;
        //尝试分析处理报文 可能报文不完整
        HandlerRequest(conn);
    }
    static void Sender(Connection* conn)
    {
        errno=0;//保证
        string& outbuffer=conn->OutBuffer();
        while(true)
        {
            ssize_t n=send(conn->SockFd(),outbuffer.c_str(),outbuffer.size(),0);
            if(n>=0)
            {
                outbuffer.erase(0,n);//已经发出的数据，就直接删除
                if(outbuffer.empty())break;
            }   
            else
            {
                if(errno==EAGAIN)break;//只有这里，才会正常退出
                else if(errno==EINTR)continue;
                else
                {
                    conn->_execepter(conn);
                    return;
                }
            }
        }
        //走到这里，意味什么？我们本轮发满了，但是数据可能没发完，为什么没发完呢？
        //开启对conn->SockFd() EPOLLOUT的关心，如何开启对写事件的关心呢
        if(!conn->OutBufferEmpty())
        {
            conn->_R->EnableReadWrite(conn->SockFd(),true,true);
        }
        else
        {
            conn->_R->EnableReadWrite(conn->SockFd(),true,false);
        }
    }
    static void Execepter(Connection* conn)
    {
        lg.LogMessage(Info,"connection erase done, who:%d \n",conn->SockFd());
        errno=0;
        //从epoll中移除conn->SockFd的关心
        //unordered_map移除conn
        conn->_R->RemoveConnection(conn->SockFd());
        
        //关闭conn->SockFd
        conn->Close();
        //delete conn释放对象
        delete conn;

       
    }
};